import java.util.LinkedList;
import java.util.List;

/*
 * Class which handles the state of a standard checkers game on an 8x8 board evaluating possible moves 
 * and outcomes of each player.
 */


public class CheckersState {
	
	private String p1; //First player of a game, Black pieces.
	private String p2; //Second player of a game, White pieces.
	private String curP; //Current player of a state.
	private int[][] cBoard; // Current state of the game board
							// 0 = empty space;
							// 1 = Black pieces;
							// 2 = White pieces;
							// 3 = King Black pieces;
							// 4 = King White pieces;
	
	public CheckersState(String board, String play1, String play2, String curPlay){
		p1 = play1;
		p2 = play2;
		curP = curPlay;
		cBoard = parseAsBoard(board);
	}
	
	// Returns the current player to move on a certain state
	public String player(){
		return curP;
	}
	
	//Returns a list of all possible actions
	public List<Move> actions(){
		
		LinkedList<Move> act = new LinkedList<Move>();
		
		
		
		
		for(int i = 0; i < 8; i++){
			for(int j = 0; j < 8; j++){
				if (curP.equals(p1)){
					if(cBoard[i][j] == 1){
						if( i+1 < 8 && j-1 >= 0){
							if(cBoard[i+1][j-1] == 0){
								act.add(new Move(curP,i,j,i+1,j-1));
							}
						}
						if(i+1 < 8 && j+1 < 8){
							if(cBoard[i+1][j+1] == 0){
								act.add(new Move(curP,i,j,i+1,j+1));
							}	
						}
						if(i+2 < 8 && j-2 >= 0){
							if((cBoard[i+1][j-1] == 2 || cBoard[i+1][j-1] == 4)  && (cBoard[i+2][j-2] == 0)){
								Move temp = new Move(curP,i,j,i+2,j-2);
								act.add(temp);
							}
						}
						if(i+2 < 8 && j+2 < 8){
							if((cBoard[i+1][j+1] == 2 || cBoard[i+1][j+1] == 4) && (cBoard[i+2][j+2] == 0)){
								act.add(new Move(curP,i,j,i+2,j+2));
							}
						}
					}
					if(cBoard[i][j] == 3){
						if(i+1 < 8 && j-1 >= 0){
							if(cBoard[i+1][j-1] == 0){
								act.add(new Move(curP,i,j,i+1,j-1));
							}
						}
						if(i+1 < 8 && j+1 < 8){
							if(cBoard[i+1][j+1] == 0){
								act.add(new Move(curP,i,j,i+1,j+1));
							}
						}
						if(i-1 >= 0 && j-1 >= 0){
							if(cBoard[i-1][j-1] == 0){
								act.add(new Move(curP,i,j,i-1,j-1));
							}
						}
						if(i-1 >= 0 && j+1 < 8){
							if(cBoard[i-1][j+1] == 0){
								act.add(new Move(curP,i,j,i-1,j+1));
							}
						}
						if(i+2 < 8 && j-2 >= 0){
							if((cBoard[i+1][j-1] == 2 || cBoard[i+1][j-1] == 4) && (cBoard[i+2][j-2] == 0)){
								act.add(new Move(curP,i,j,i+2,j-2));
							}
						}
						if(i+2 < 8 && j+2 < 8){
							if((cBoard[i+1][j+1] == 2 || cBoard[i+1][j+1] == 4) && (cBoard[i+2][j+2] == 0)){
								act.add(new Move(curP,i,j,i+2,j+2));
							}
						}
						if(i-2 >= 0 && j-2 >= 0){
							if((cBoard[i-1][j-1] == 2 || cBoard[i-1][j-1] == 4) && (cBoard[i-2][j-2] == 0)){
								act.add(new Move(curP,i,j,i-2,j-2));
							}
						}
						if(i-2 >= 0 && j+2 < 8){
							if((cBoard[i-1][j+1] == 2 || cBoard[i-1][j+1] == 4) && (cBoard[i-2][j+2] == 0)){
								act.add(new Move(curP,i,j,i-2,j+2));
							}
						}
						
					} 
				}
				
				
				else if(curP.equals(p2)){
					if(cBoard[i][j] == 2){
						if(i-1 >= 0 && j-1 >= 0){
							if(cBoard[i-1][j-1] == 0){
								act.add(new Move(curP,i,j,i-1,j-1));
							}
						}
						if(i-1 >= 0 && j+1 < 8){
							if(cBoard[i-1][j+1] == 0){
								act.add(new Move(curP,i,j,i-1,j+1));
							}
						}
						if(i-2 >= 0 && j-2 >= 0){
							if((cBoard[i-1][j-1] == 1 || cBoard[i-1][j-1] == 3) && (cBoard[i-2][j-2] == 0)){
								act.add(new Move(curP,i,j,i-2,j-2));
							}
						}
						if(i-2 >= 0 && j+2 < 8){
							if((cBoard[i-1][j+1] == 1 || cBoard[i-1][j+1] == 3) && (cBoard[i-2][j+2] == 0)){
								act.add(new Move(curP,i,j,i-2,j+2));
							}
						}
					}
					if(cBoard[i][j] == 4){
						if(i+1 < 8 && j-1 >= 0){
							if(cBoard[i+1][j-1] == 0){
								act.add(new Move(curP,i,j,i+1,j-1));
							}
						}
						if(i+1 < 8 && j+1 < 8){
							if(cBoard[i+1][j+1] == 0){
								act.add(new Move(curP,i,j,i+1,j+1));
							}
						}
						if(i-1 >= 0 && j-1 >= 0){
							if(cBoard[i-1][j-1] == 0){
								act.add(new Move(curP,i,j,i-1,j-1));
							}
						}
						if(i-1 >= 0 && j+1 < 8){
							if(cBoard[i-1][j+1] == 0){
								act.add(new Move(curP,i,j,i-1,j+1));
							}
						}
						if(i+2 < 8 && j-2 >= 0){
							if((cBoard[i+1][j-1] == 1 || cBoard[i+1][j-1] == 3) && (cBoard[i+2][j-2] == 0)){
								act.add(new Move(curP,i,j,i+2,j-2));
							}
						}
						if(i+2 < 8 && j+2 < 8){
							if((cBoard[i+1][j+1] == 1 || cBoard[i+1][j+1] == 3) && (cBoard[i+2][j+2] == 0)){
								act.add(new Move(curP,i,j,i+2,j+2));
							}
						}
						if(i-2 >= 0 && j-2 >= 0){
							if((cBoard[i-1][j-1] == 1 || cBoard[i-1][j-1] == 3) && (cBoard[i-2][j-2] == 0)){
								act.add(new Move(curP,i,j,i-2,j-2));
							}
						}
						if(i-2 >= 8 && j+2 < 8){
							if((cBoard[i-1][j+1] == 1 || cBoard[i-1][j+1] == 3) && (cBoard[i-2][j+2] == 0)){
								act.add(new Move(curP,i,j,i-2,j+2));
							}
						}
						
						
					}
				}
			}
		}
		
		return act;
	}
	
	//Outputs a new state of the game after a certain action is performed.
	public CheckersState result(Move action){
		int[][] nextState = copyState(cBoard);
		
		while(!action.isJumpListEmpty()){
			EnemyLocation eTemp = action.dequeueEnemyJump();
			nextState[eTemp.getEnemRow()][eTemp.getEnemCol()] = 0;
		}
		
		nextState[action.getDestRow()][action.getDestCol()]= nextState[action.getIntialRow()][action.getIntialCol()];
		nextState[action.getIntialRow()][action.getIntialCol()] = 0;
		return new CheckersState(parseToString(nextState),p1,p2,nextPlayer());
	}
	
	// Outputs a graphical representation of the game a the current state.
	public void printBoard(){
		System.out.println("-------------------------");
		for(int i = 0; i < 8 ; i++){
			for(int j = 0; j < 8; j++){
				if (cBoard[i][j] == 0){
					System.out.print("|  ");
				}
				if (cBoard[i][j] == 1){
					System.out.print("| B");
				}
				if (cBoard[i][j] == 2){
					System.out.print("| W");
				}
				if (cBoard[i][j] == 3){
					System.out.print("|KW");
				}
				if (cBoard[i][j] == 4){
					System.out.print("|KW");
				}
			}
			System.out.println("|");
			System.out.println("-------------------------");
		}
	}
	
	//Parses a formatted string into a representation of a checkers board.
	//String input will be of certain format where, 
	//E = empty, B = black, W = white, N = king black, W = king white.
	private int[][] parseAsBoard(String s){
		int ind = 0;
		int[][] b = new int[8][8];
		for (int i = 0; i < 8; i++){
			for(int j = 0; j < 8; j++){
				if (s.charAt(ind) == 'E')
					b[i][j] = 0;
				if (s.charAt(ind) == 'B')
					b[i][j] = 1;
				if (s.charAt(ind) == 'W')
					b[i][j] = 2;
				if (s.charAt(ind) == 'N')
					b[i][j] = 3;
				if (s.charAt(ind) == 'M')
					b[i][j] = 4;
				ind++;
			}
		}
		
		return b;
		
	}
	
	private String parseToString(int[][] parsee){
		String s = "";
		for(int i = 0; i < 8; i++){
			for(int j = 0; j < 8; j++){
				if(parsee[i][j] == 0){
					s += "E";
				}
				if(parsee[i][j] == 1){
					s += "B";
				}
				if(parsee[i][j] == 2){
					s += "W";
				}
				if(parsee[i][j] == 3){
					s += "N";
				}
				if(parsee[i][j] == 4){
					s += "M";
				}
			}
		}
		return s;
	}
	
	private int[][] copyState(int[][] toCopy){
		int[][] copy = new int[8][8];
		for(int i = 0; i < 8; i++){
			for(int j = 0; j < 8; j++){
				copy[i][j] = toCopy[i][j];
			}
		}
		return copy;
	}
	
	
	private String nextPlayer(){
		if(curP.equals(p1)){
			return p2;
		}
		else{
			return p1;
		}
	}
	
		
	
}
